package com.itheima.search.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.search.Hit;
import com.itheima.search.domain.*;
import com.itheima.search.service.SearchService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@Service
@RequiredArgsConstructor
public class SearchServiceImpl implements SearchService {

    private final ElasticsearchClient esClient;
    //索引名 news
    private static final String INDEX_NAME = "news";
    @Override
    public SearchResult search(SearchParam searchParam) {
        SearchResult result = SearchResult.empty();
        try {
            SearchRequest.Builder builder = new SearchRequest.Builder().index(INDEX_NAME);
            BoolQuery.Builder boolQuery = new BoolQuery.Builder();
            Boolean isHighlight = false;
            if (StrUtil.isNotBlank(searchParam.getKeyword())) {
                // 匹配内容,标题
                boolQuery.must(q -> q
                        .multiMatch(m -> m
                                .query(searchParam.getKeyword())
                                .fields("title", "content")));
                isHighlight = true;
            }
            // 设置分页
            int from = (searchParam.getPageNo() - 1) * searchParam.getPageSize();
            int size = searchParam.getPageSize();

            builder.from(from).size(size);
            // 排序
//            builder.sort(s -> s
//                    .field(f -> f
//                            .field("createTime")
//                            .order(SortOrder.Desc)));

            // 设置高亮
            if (isHighlight) {
                builder.highlight(h -> h
                        .fields("title", f -> f
                                .preTags("<em>")
                                .postTags("</em>"))
                        .fields("content", f -> f
                                .preTags("<em>")
                                .postTags("</em>")));
            }

            builder.query(q -> q.bool(boolQuery.build()));
            //2、发送请求
            SearchResponse<NewsVO> response = esClient.search(builder.build(), NewsVO.class);
            // 解析结果
            // 1、总条数
            Long total = response.hits().total().value();
            result.setTotal(total);
            // 2、总页数
            Long pages = total % searchParam.getPageSize() == 0 ? total / searchParam.getPageSize() : total / searchParam.getPageSize() + 1;
            result.setPages(pages);
            // 3、数据
            List<NewsVO> newsVOList = new ArrayList<>();
            for (Hit<NewsVO> hit : response.hits().hits()) {
                NewsVO vo = hit.source();
                if (isHighlight) {
                    if (hit.highlight() != null && hit.highlight().containsKey("title")) {
                        // 设置为高亮后的标题
                        vo.setTitle(hit.highlight().get("title").get(0));
                    }
                    if (hit.highlight() != null && hit.highlight().containsKey("content")) {
                        // 设置为高亮后的内容
                        String content = hit.highlight().get("content").get(0);
//                        content.replaceAll("[^>]*>", "");
                        vo.setContent(content);
                    }
//                    else {
//                        // 对内容进行处理，不让它展示过长
////                        String content = vo.getContent();
////                        String[] split = content.split("<[^>]*>");
////                        content = split[0] + split[1] + split[2] + "......";
////                        vo.setContent(content);
//                    }
                }
                newsVOList.add(vo);
            }
            result.setRecords(newsVOList);
        } catch (IOException e) {
            throw new RuntimeException("查询es中新闻失败！", e);
        }
        return result;
    }

    @Override
    public NewsVO getById(String newsId) {
        NewsVO vo;
        try {
            GetResponse<NewsVO> response = esClient.get(g -> g
                            .index(INDEX_NAME)
                            .id(newsId),
                    NewsVO.class
            );
            if (response.found()) {
                vo = response.source();
            } else {
                throw new RuntimeException("商品不存在！");
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return vo;
    }

    @Override
    public void deleteNews(String newsId) {
        //根据id删除es中的数据
        try {
            esClient.delete(d -> d.index(INDEX_NAME).id(newsId.toString()));
        }catch (Exception e){
            throw new RuntimeException("根据id删除es中的数据失败"+e.getMessage());
        }
    }

    @Override
    public void updateNewsById(String newIds) {
        //根据id查询数据库的数据
        NewsVO newsVO = getById(newIds);
        //更新es中的数据
        if (newsVO!=null){
            //根据id删除原来的数据
            deleteNews(newsVO.getNewsId());
            addNewsToEs(newIds);
        }


    }

    //根据id添加数据到es中
    @Override
    public void addNewsToEs(String newsId){
        try {
            NewsVO newsVO = getById(newsId);
            NewsDoc newsDoc = BeanUtil.toBean(newsVO, NewsDoc.class);

            esClient.index(i -> i.index(INDEX_NAME).id(newsDoc.getNewsId().toString()).document(newsDoc));
        }catch (Exception e){
            throw new RuntimeException("根据id添加数据到es中失败"+e.getMessage());
        }
    }

    /**
     * 添加文档
     * @param news
     */
    @Override
    public void AddDocument(News news) {
        NewsDoc newsDoc = new NewsDoc();
        BeanUtils.copyProperties(news, newsDoc);
        newsDoc.setNewsId(news.getNewsId().toString());
        long status = news.getStatus().getStatus();
        newsDoc.setStatus((int) status);
        try {
            IndexResponse indexResponse = esClient.index(indexRequest -> {
                return indexRequest
                        .index(INDEX_NAME)
                        .id(newsDoc.getNewsId().toString())
                        .document(newsDoc);
            });
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void delDocument(String newsId) {
        try {
            DeleteResponse deleteResponse = esClient.delete(deleteRequest -> {
                return deleteRequest
                        .index(INDEX_NAME)
                        .id(newsId);
            });
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
